﻿using System;
using System.Threading;
using System.Threading.Tasks;
using Apache.IoTDB;
using Iot.Shared.Path;
using Microsoft.Extensions.Logging;

namespace Iot.TimingDatabase.Helper;

public static class InitializeHelper
{
    private const string Ttl = "TTL(ms)";

    /// <summary>
    /// </summary>
    /// <param name="session"></param>
    /// <param name="path">路径root必须小写</param>
    /// <param name="days">数据保存时长</param>
    /// <param name="logger"> logger</param>
    /// <returns></returns>
    public static async Task Initialize(this SessionPool session, DevicePath path, int days, ILogger logger)
    {
        try
        {
            #region 判断数据库路径是否合法

            // 获取路径字符串
            var name = path.ToString();
            // 判断路径是否以"root."开头
            if (!name.IsOriginalRootPath())
            {
                // 如果不以"root."开头，则记录日志并返回
                logger.LogInformation("数据库名不符合规范：{name}", name);
                return; // 如果设备ID不以"root."开头，则直接返回       要报错
            }

            #endregion

            #region 打开数据库并创建库(如不存在)

            // 记录日志，准备开始链接数据库
            logger.LogInformation("准备开始链接数据库：{path},数据设置保存时长：{days}天", path, days);
            // 创建一个CancellationTokenSource，设置超时时间为10秒
            using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
            // 打开数据库连接
            await session.Open(false, cts.Token);
            // 记录日志，数据库链接成功
            logger.LogInformation("数据库链接成功：{path}", path);
            // 记录日志，查询数据是否存在
            logger.LogInformation("查询数据：{path},是否存在", name);
            // 执行查询语句，查询数据库是否存在
            var databases = await session.ExecuteQueryStatementAsync("show databases " + name);
            // 如果查询结果为空，则创建数据库
            if (databases.RowCount == 0)
            {
                // 记录日志，数据不存在，开始创建
                logger.LogInformation("数据：{path},不存在，开始创建", name);
                // 执行创建数据库的语句
                var ttlStatus = await session.ExecuteNonQueryStatementAsync("CREATE DATABASE " + name);
                // 记录日志，创建数据库的状态
                logger.LogInformation("创建数据：{path},状态：{status}", name, ttlStatus == 0 ? "成功" : "失败");
            }
            else
            {
                // 记录日志，数据存在
                logger.LogInformation("数据：{path},存在", name);
            }

            #endregion

            #region 查询设置数据保存时间

            // 记录日志，查询数据保存时间
            logger.LogInformation("查询数据：{path},数据保存时间", name);
            // 执行查询语句，查询数据保存时间
            var ttlInfo = await session.ExecuteQueryStatementAsync("SHOW TTL ON " + name); //SHOW TTL ON  root.`轨道电路`


            // 初始化数据保存时间为0天
            var readInfoRow = TimeSpan.FromDays(0);
            // 如果查询结果不为空，则解析数据保存时间
            if (ttlInfo.RowCount != 0)
            {
                // 获取TTL列的索引
                var index = ttlInfo.ColumnNames.IndexOf(Ttl);
                // 如果索引大于等于0，则获取下一行数据
                if (index >= 0)
                {
                    var row = ttlInfo.Next();
                    // 获取TTL列的值
                    var str = row.Values[index]?.ToString();
                    // 如果值可以转换为long类型，则转换为TimeSpan类型
                    if (long.TryParse(str, out var ttl))
                    {
                        readInfoRow = TimeSpan.FromMilliseconds(ttl);
                    }
                }
            }

            // 计算数据保存天数
            var writeTtl = TimeSpan.FromDays(days); //数据保存天数
            // 记录日志，数据保存时间
            logger.LogInformation("数据：{path},数据保存时间：{readInfoRow}", name, readInfoRow);
            // 如果数据保存时间与设置的不一致，则修改数据保存时间
            if (writeTtl != readInfoRow)
            {
                // 记录日志，数据保存时间与设置的不一致，开始修改
                logger.LogInformation("数据：{path},数据保存时间：{readInfoRow}，与设置：{writeTtl}不一致，开始修改", name, readInfoRow,
                    writeTtl);
                // 执行修改数据保存时间的语句
                var ttlStatus =
                    await session.ExecuteNonQueryStatementAsync(
                        $"SET TTL TO {name} {(long)Math.Truncate(writeTtl.TotalMilliseconds)}");

                // 记录日志，修改数据保存时间的状态
                logger.LogInformation("数据：{path},数据保存时间：{writeTtl}，修改状态：{status}", name, writeTtl,
                    ttlStatus == 0 ? "成功" : "失败");
            }

            #endregion
        }
        catch (Exception e)
        {
            // 记录日志，初始化数据库失败
            logger.LogCritical(e, "初始化数据库失败");
        }
    }
}